#include <queue>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <vector>
#include "API.h"
#include "BaselineRandomWalk.h"
#include "Lottery.h"
#include "Greedy.h"
#include "Greedy2.h"
#include "Greedy4.h"

using namespace std;

#ifdef __UNITTEST__

int main(int argc, char* argv[]) {
    //PNEGraph G = TSnap::GenRndGnm<PNEGraph>(10,20);
    
    PNGraph Gtmp = TSnap::GenForestFire(100, 0.35, 0.32);
    //PNEGraph G = TSnap::ConvertGraph<PNEGraph>(Gtmp);
    //TSnap::SaveEdgeList<PNEGraph>(G, "testGraph.bin");
    
    //G = TNEGraph::New();
    //G = TSnap::LoadEdgeList<PNEGraph>("testGraph.bin");
    
    /*
    TIntStrH name;
    for(int i = 0; i < 10; i++) {
        char *tmp = new char[10];
        sprintf(tmp, "v%d", i);
        name.AddDat(i) = tmp;
    }
    TGraphViz::Plot<PNEGraph>(G, gvlDot, "graphPlot.png", "", name);
    */

    API *a = new API(TSnap::ConvertGraph<PNEGraph>(Gtmp));

    LotteryRandomWalk lott(a);
    lott.crawl(100);

    TGnuPlot Gp("NodesExploredlower", "Nodes Explored");
	Gp.AddPlot(lott.getNodeStatistics(), gpwLinesPoints, "Lottery");
    Gp.SetXYLabel("Cost", "Nodes found");
    Gp.SavePng();

    Gp = TGnuPlot("EdgesExploredlower", "Edges Explored");
	Gp.AddPlot(lott.getEdgeStatistics(), gpwLinesPoints, "Lottery");
    Gp.SetXYLabel("Cost", "Edges found");
    Gp.SavePng();
    return 0;
}

#endif

#ifdef _TEST_ALL_

// Separator separated file. One edge per line
// SrcColId and DstColId are column indexes of source/destination INTEGER node id
PNEGraph LoadTwitter(const TStr& InFNm, const int& SrcColId, const int& DstColId, const char& Separator) {
  TSsParser Ss(InFNm, Separator);
  PNEGraph Graph = PNEGraph::TObj::New();
  Graph->Reserve(41800000,1480000000);
  int SrcNId, DstNId;
  while (Ss.Next()) {
    if (! Ss.GetInt(SrcColId, SrcNId) || ! Ss.GetInt(DstColId, DstNId)) { continue; }
    if (! Graph->IsNode(SrcNId)) { Graph->AddNode(SrcNId); }
    if (! Graph->IsNode(DstNId)) { Graph->AddNode(DstNId); }
    Graph->AddEdge(SrcNId, DstNId);
  }
  Graph->Defrag();
  return Graph;
}

int main(int argc, char* argv[]) {
	
	Env = TEnv(argc, argv, TNotify::StdNotify);
	Env.PrepArgs(TStr::Fmt("Test All Methods. build: %s, %s. Time: %s", __TIME__, __DATE__, TExeTm::GetCurTm()));
	TExeTm ExeTm;
	Try
    
	/*
	const int nodes = 1000000;
    const int MAX_COST = nodes*4;
	
    PNGraph Gtmp = TSnap::GenForestFire(nodes, 0.35, 0.32);
    PNEGraph Graph = TSnap::ConvertGraph<PNEGraph>(Gtmp);
    */
	const int MAX_COST = 1000000;
	printf("Twitter Graph Loading...\n");
	PNEGraph Graph = LoadTwitter("/lfs/1/tmp/saint/twitter/twitter_rv.net",0,1,'\t');
	printf("Twitter Graph Loaded\n");
	cout<<"Nodes: "<<Graph->GetNodes()<<endl;
	cout<<"Edges: "<<Graph->GetEdges()<<endl;

	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/graph.bin");
		Graph->Save(FOut1); 
	}
	printf("Twitter Graph Saved to binary\n");
		
	/*
	TFIn FIn1("/lfs/1/tmp/saint/twitter/graph.bin");
	PNEGraph Graph = TNEGraph::Load(FIn1);
	*/
	
	//API api(Graph);
    API *baseapi = new API(Graph);
    baseapi->disableCache();
    API *lotapi = new API(Graph);
    lotapi->disableCache();
    API *telapi = new API(Graph);
    telapi->disableCache();
    API *greedapi = new API(Graph);
    greedapi->enableCache();
    API *greed2api = new API(Graph);
    greed2api->enableCache();
    API *greed4api = new API(Graph); 
    greed4api->enableCache();
    
    BaselineRandomWalk base(baseapi);
    LotteryRandomWalk lott(lotapi);
    AlwaysTeleportRandomWalk tel(telapi);
    Greedy greed(greedapi);
    Greedy2 greed2(greed2api);
    Greedy4 greed4(greed4api);

	cout << "Crawling using greedy4..." << endl;
    greed4.crawl(MAX_COST);
    cout << "Done" << endl;
	TFltPrV TVec = greed4.getNodeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/greed4_n.bin");
		TVec.Save(FOut1); 
	}
	TVec = greed4.getEdgeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/greed4_e.bin");
		TVec.Save(FOut1); 
	}

    cout << "Crawling using baseline random walk..." << endl;
    base.crawl(MAX_COST);
	cout << "Done" << endl;
	TVec = base.getNodeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/base_n.bin");
		TVec.Save(FOut1); 
	}
	TVec = base.getEdgeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/base_e.bin");
		TVec.Save(FOut1); 
	}

    cout << "Crawling using teleport..." << endl;
    tel.crawl(MAX_COST);
	cout << "Done" << endl;
	TVec = tel.getNodeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/tel_n.bin");
		TVec.Save(FOut1); 
	}
	TVec = tel.getEdgeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/tel_e.bin");
		TVec.Save(FOut1); 
	}

	cout << "Crawling using lottery..." << endl;
	lott.crawl(MAX_COST);
	cout << "Done" << endl;
	TVec = lott.getNodeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/lott_n.bin");
		TVec.Save(FOut1); 
	}
	TVec = lott.getEdgeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/lott_e.bin");
		TVec.Save(FOut1); 
	}

	cout << "Crawling using greedy..." << endl;
    greed.crawl(MAX_COST);
    cout << "Done" << endl;
	TVec = greed.getNodeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/greed_n.bin");
		TVec.Save(FOut1); 
	}
	TVec = greed.getEdgeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/greed_e.bin");
		TVec.Save(FOut1); 
	}

	cout << "Crawling using greedy2..." << endl;
    greed2.crawl(MAX_COST);
    cout << "Done" << endl;
	TVec = greed2.getNodeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/greed2_n.bin");
		TVec.Save(FOut1); 
	}
	TVec = greed2.getEdgeStatistics();
	{
		TFOut FOut1("/lfs/1/tmp/saint/twitter/greed2_e.bin");
		TVec.Save(FOut1); 
	}

	TGnuPlot Gp("NodesExplored", "Nodes Explored");
    Gp.AddPlot(tel.getNodeStatistics(), gpwLines, "Teleport");
    Gp.AddPlot(base.getNodeStatistics(), gpwLines, "Random Walk");
    Gp.AddPlot(greed.getNodeStatistics(), gpwLines, "Greedy");
    Gp.AddPlot(lott.getNodeStatistics(), gpwLines, "Lottery");
    Gp.AddPlot(greed2.getNodeStatistics(), gpwLines, "Greedy2");
    Gp.AddPlot(greed4.getNodeStatistics(), gpwLines, "Greedy4");
    
    
    Gp.SetXYLabel("Cost", "Nodes found");
    Gp.SavePng();

    Gp = TGnuPlot("EdgesExplored", "Edges Explored");
    Gp.AddPlot(tel.getEdgeStatistics(), gpwLines, "Teleport");
    Gp.AddPlot(base.getEdgeStatistics(), gpwLines, "Random Walk");
    Gp.AddPlot(greed.getEdgeStatistics(), gpwLines, "Greedy");
    Gp.AddPlot(lott.getEdgeStatistics(), gpwLines, "Lottery");
    Gp.AddPlot(greed2.getEdgeStatistics(), gpwLines, "Greedy2");
    Gp.AddPlot(greed4.getEdgeStatistics(), gpwLines, "Greedy4");

    Gp.SetXYLabel("Cost", "Edges found");
    Gp.SavePng();
	
	Catch
	printf("\nrun time: %s (%s)\n", ExeTm.GetTmStr(), TSecTm::GetCurTm().GetTmStr().CStr());

    return 0;
}

#endif
